import numpy as np
import math


# 目标函数定义
def fitness_func(x, y):
    numerator = 6.452 * (x + 0.125 * y) * (math.cos(x) - math.cos(2 * y) ** 2)
    denominator = math.sqrt(0.8 + (x - 4.2) ** 2 + 2 * (y - 7) ** 2)
    return numerator / denominator + 3.226 * y


# 遗传算法参数
POP_SIZE = 100  # 种群大小
MAX_GEN = 200  # 最大迭代次数
CROSS_RATE = 0.8  # 交叉概率
MUTATION_RATE = 0.1  # 变异概率
VAR_RANGES = [(0, 10), (0, 15)]  # x和y的取值范围
TOURNAMENT_SIZE = 3  # 锦标赛选择规模
MUTATION_STD = 0.5  # 高斯变异标准差


# 初始化种群
def initialize_population():
    population = np.zeros((POP_SIZE, 2))
    for i in range(POP_SIZE):
        population[i, 0] = np.random.uniform(*VAR_RANGES[0])  # x
        population[i, 1] = np.random.uniform(*VAR_RANGES[1])  # y
    return population


# 锦标赛选择
def tournament_selection(pop, fitness):
    idx = np.random.choice(len(pop), TOURNAMENT_SIZE, replace=False)
    candidates = fitness[idx]
    return pop[idx[np.argmax(candidates)]]


# 模拟二进制交叉（SBX）
def sbx_crossover(parent1, parent2):
    if np.random.rand() < CROSS_RATE:
        eta = 1.0  # 分布指数
        child1, child2 = parent1.copy(), parent2.copy()
        for i in range(len(parent1)):
            u = np.random.rand()
            beta = (2 * u) ** (1 / (eta + 1)) if u < 0.5 else (1 / (2 * (1 - u))) ** (1 / (eta + 1))
            child1[i] = 0.5 * ((1 + beta) * parent1[i] + (1 - beta) * parent2[i])
            child2[i] = 0.5 * ((1 - beta) * parent1[i] + (1 + beta) * parent2[i])
            # 确保不越界
            child1[i] = np.clip(child1[i], *VAR_RANGES[i])
            child2[i] = np.clip(child2[i], *VAR_RANGES[i])
        return child1, child2
    else:
        return parent1.copy(), parent2.copy()


# 高斯变异
def gaussian_mutation(child):
    for i in range(len(child)):
        if np.random.rand() < MUTATION_RATE:
            child[i] += np.random.normal(0, MUTATION_STD)
            child[i] = np.clip(child[i], *VAR_RANGES[i])
    return child


# 主算法流程
def genetic_algorithm():
    population = initialize_population()
    best_fitness = -np.inf
    best_individual = None
    fitness_history = []

    for gen in range(MAX_GEN):
        # 计算适应度
        fitness = np.array([fitness_func(ind[0], ind[1]) for ind in population])

        # 记录最佳个体
        current_max = np.max(fitness)
        if current_max > best_fitness:
            best_fitness = current_max
            best_individual = population[np.argmax(fitness)]

        fitness_history.append(current_max)

        # 生成新一代种群
        new_population = []
        for _ in range(POP_SIZE // 2):
            # 选择
            parent1 = tournament_selection(population, fitness)
            parent2 = tournament_selection(population, fitness)

            # 交叉
            child1, child2 = sbx_crossover(parent1, parent2)

            # 变异
            child1 = gaussian_mutation(child1)
            child2 = gaussian_mutation(child2)

            new_population.extend([child1, child2])

        population = np.array(new_population)

        # 输出进度
        if gen % 50 == 0:
            print(f'Generation {gen}: Best Fitness = {current_max:.2f}')

    return best_individual, best_fitness, fitness_history


# 运行算法并输出结果
best_ind, best_fit, history = genetic_algorithm()
print('\n=== 最终结果 ===')
print(f'最大函数值: {best_fit:.2f}')
print(f'对应坐标 (x, y): ({best_ind[0]:.2f}, {best_ind[1]:.2f})')

# 可视化适应度曲线（可选）
import matplotlib.pyplot as plt

plt.plot(history)
plt.xlabel('Generation')
plt.ylabel('Best Fitness')
plt.title('Convergence Curve')
plt.show()